#include "qqmusic.h"
#include "ui_qqmusic.h"
#include <QPoint>
#include <QMouseEvent>
#include <QGraphicsDropShadowEffect>
#include "btform.h"
#include <QDebug>
#include <QJsonObject>
#include <QJsonArray>
#include <QFileDialog>
#include <QMessageBox>
#include <QSqlQuery>
#include <QSystemTrayIcon>
#include <QMenu>


QQMusic::QQMusic(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::QQMusic)
    , currentIndex(-1)
{
    ui->setupUi(this);
    //界面初始化
    initUI();
    //初始化数据库
    initSqlite();
    //初始化歌曲列表MusicList
    initMusicList();
    //初始化媒体播放相关操作
    initPlayer();
    //内部添加所有的信号和槽函数的连接函数
    connectSignalAndSlots();
}

QQMusic::~QQMusic()
{
    delete ui;
}

//界面初始化
void QQMusic::initUI()
{
    //设置窗口格式为无边框的窗口
    this->setWindowFlag(Qt::WindowType::FramelessWindowHint);
    //设置完窗口为无边框的窗口时，程序无法进行拖拽和关闭

    //给这个窗口周围设置毛玻璃阴影效果
    //首先需要将这个窗口背景设置为透明色
    this->setAttribute(Qt::WA_TranslucentBackground);

    //设置图标
    this->setWindowIcon(QIcon(":/images/tubiao.png"));

    //禁用最大化按钮
    ui->max->setEnabled(false);

    //添加系统托盘
    QSystemTrayIcon* trayIcon=new QSystemTrayIcon(this);
    //设置图标
    trayIcon->setIcon(QIcon(":/images/tubiao.png"));
    //显示系统托盘
    trayIcon->show();
    //给托盘添加菜单
    //创建菜单
    QMenu* trayMenu=new QMenu();
    //给菜单中添加菜单项并为每个菜单项关联处理方法
    trayMenu->addAction("显示",this,&QWidget::showNormal);
    trayMenu->addAction("退出",this,&QQMusic::onQQMusicQuit);
    //将菜单设置到托盘中
    trayIcon->setContextMenu(trayMenu);


    //给窗口设置阴影效果
    QGraphicsDropShadowEffect *shadowEffect=new QGraphicsDropShadowEffect(this);
    shadowEffect->setOffset(0,0);//设置阴影偏移位置
    shadowEffect->setColor("#000000");//设置阴影颜色为黑色
    shadowEffect->setBlurRadius(10);//设置阴影模糊半径(四角周围)
    //将上述阴影效果设置给此窗口
    this->setGraphicsEffect(shadowEffect);

    //设置BtForm按钮的图标和文本信息，并为此按钮设置id值
    ui->rec->setIconAndText(":/images/rec.png","推荐",0);
    ui->radio->setIconAndText(":/images/radio.png","电台",1);
    ui->music->setIconAndText(":/images/music.png","音乐馆",2);
    ui->like->setIconAndText(":/images/like.png","我喜欢",3);
    ui->local->setIconAndText(":/images/local.png","本地下载",4);
    ui->recent->setIconAndText(":/images/recent.png","最近播放",5);

    //默认显示本地下载按钮所关联的page
    ui->stackedWidget->setCurrentIndex(4);

    //将本地下载设置为默认当前页面
    currentPage=ui->localPage;

    //显示本地下载按钮的动画效果
    ui->local->showAnimal(true);

    //随机加载图片和文本-RecBoxItem元素
    //randomPiction();

    //设置随机数种子-用于每次初始化推荐页面都不相同
    srand(time(NULL));

    //初始化两个RecBox控件
    ui->recMusicBox->initRecBoxUi(randomPiction(),1);
    ui->supplyMusicBox->initRecBoxUi(randomPiction(),2);

    //设置CommonPage的信息[我喜欢、本地下载、最近播放]
    ui->likePage->setCommonPageUI("我喜欢",":/images/ilikebg.png");
    ui->localPage->setCommonPageUI("本地下载",":/images/localbg.png");
    ui->recentPage->setCommonPageUI("最近播放",":/images/recentbg.png");

    //播放控制区按钮图标的设定
    //播放按钮默认设置
    ui->play->setIcon(QIcon(":/images/play_2.png"));
    //播放模式默认设置为随机播放
    ui->playMode->setIcon(QIcon(":/images/shuffle_2.png"));

    //初始化调节音量窗口对象
    volumeTool=new VolumeTool(this);

    //初始化lrc歌词界面
    lrcPage=new LrcPage(this);
    //设置lrc歌曲页面的位置和尺寸
    lrcPage->setGeometry(10,10,lrcPage->width(),lrcPage->height());
    //默认状态让lrc歌词界面隐藏起来
    lrcPage->hide();

    //初始化上移动画对象 与lrc歌词界面相互关联，动画是一个矩形，放到对象树上去
    lrcPageAnimal=new QPropertyAnimation(lrcPage,"geometry",this);
    //设置动画周期500ms
    lrcPageAnimal->setDuration(500);
    //设置动画起始帧
    lrcPageAnimal->setStartValue(QRect(10,10+lrcPage->height(),lrcPage->width(),lrcPage->height()));
    //设置动画结束帧
    lrcPageAnimal->setEndValue(QRect(10,10,lrcPage->width(),lrcPage->height()));
    //不设置动画次数，默认就是一次

}
//初始化数据库
void QQMusic::initSqlite()
{
    //1、进行数据库驱动加载
    QSqlDatabase sqlite=QSqlDatabase::addDatabase("QSQLITE");
    //2、设置数据库名称
    sqlite.setDatabaseName("QQMusic.db");
    //3、连接(打开)数据库
    if(sqlite.open()==false)
    {
        //打开失败，弹出一个打开失败的提示框
        QMessageBox::critical(this,"QQMusic","数据库打开失败");
        return;
    }
    qDebug()<<"QQMusic数据库连接成功";
    //4、创建表
    QString sql="create table if not exists MusicInfo(\
                    id integer primary key autoincrement,\
                    musicId varchar(50) unique,\
                    musicName varchar(50),\
                    musicSinger varchar(50),\
                    albumName varchar(50),\
                    musicUrl varchar(256),\
                    duration bigint,\
                    isLike integer,\
                    isHistory integer)";
    //执行创建表的sql语句
    QSqlQuery query;
    if(query.exec(sql)==false)
    {
        //执行失败，显示提示窗口
        QMessageBox::critical(this,"QQMusic","初始化错误");
        return;
    }
    qDebug()<<"QQMusic表创建成功";
}
//初始化歌曲列表MusicList
void QQMusic::initMusicList()
{
    //将数据库中的信息放到MusicList中
    musicList.readFromDB();

    //设置[我喜欢、本地下载、最经播放]界面并设置界面的类型 然后刷新界面
    ui->likePage->setMusicListType(PageType::LIKE_PAGE);
    ui->likePage->reFresh(musicList);

    ui->localPage->setMusicListType(PageType::LOCAL_PAGE);
    ui->localPage->reFresh(musicList);

    ui->recentPage->setMusicListType(PageType::HISTORY_PAGE);
    ui->recentPage->reFresh(musicList);
}
//初始化媒体播放相关操作
void QQMusic::initPlayer()
{
    //1、初始化媒体播放相关类的对象
    //初始化媒体播放类
    player=new QMediaPlayer(this);
    //初始化播放列表
    playList=new QMediaPlaylist(this);
    //2、设置默认播放模式(QMediaPlaylist::Random表示随机播放)
    playList->setPlaybackMode(QMediaPlaylist::Random);
    //3、将播放列表设置到播放媒体对象中
    player->setPlaylist(playList);
    //4、设置默认的音量大小 默认设置为20%
    player->setVolume(20);

    //关联QMediaPlayer的信号
    connect(player,&QMediaPlayer::stateChanged,this,&QQMusic::onPlayerStateChanged);

    //关联QMediaPlayer::durationChanged信号的槽函数
    //当媒体源播放内容发生改变时对应信号的槽函数
    connect(player,&QMediaPlayer::durationChanged,this,&QQMusic::onDurationChanged);

    //关联QMediaPlayer::positionChanged信号
    //播放进度发生改变时的信号对应的槽函数的关联
    connect(player,&QMediaPlayer::positionChanged,this,&QQMusic::onPositionChanged);

    //关联QMediaPlayer::onMetaDataAvailableChanged
    //当媒体源发生改变时的信号与槽函数进行关联
    connect(player,&QMediaPlayer::metaDataAvailableChanged,this,&QQMusic::onMetaDataAvailableChanged);

    //当playlist中播放源发生变化时信号和槽函数的关联
    connect(playList,&QMediaPlaylist::currentIndexChanged,this,&QQMusic::onCurrentIndexChanged);



}
//内部添加所有的信号和槽函数的连接函数
void QQMusic::connectSignalAndSlots()
{
    //关联BtForm各个按钮的btClick点击信号和槽函数
    connect(ui->rec,&BtForm::btclick,this,&QQMusic::onBtFormClick);
    connect(ui->radio,&BtForm::btclick,this,&QQMusic::onBtFormClick);
    connect(ui->music,&BtForm::btclick,this,&QQMusic::onBtFormClick);
    connect(ui->like,&BtForm::btclick,this,&QQMusic::onBtFormClick);
    connect(ui->local,&BtForm::btclick,this,&QQMusic::onBtFormClick);
    connect(ui->recent,&BtForm::btclick,this,&QQMusic::onBtFormClick);

    //点击我喜欢按钮后，对我喜欢、本地下载、最近播放三个page页面所管理的Music列表信息进行调整。信号和槽函数关联起来
    connect(ui->localPage,&CommonPage::updataLikeMusic,this,&QQMusic::updateLikeMusicAndPage);
    connect(ui->likePage,&CommonPage::updataLikeMusic,this,&QQMusic::updateLikeMusicAndPage);
    connect(ui->recentPage,&CommonPage::updataLikeMusic,this,&QQMusic::updateLikeMusicAndPage);

    //播放控制区信号和槽函数的关联
    //点击播放按钮的槽函数
    connect(ui->play,&QPushButton::clicked,this,&QQMusic::onPlayMusic);
    //点击上一曲按钮的槽函数
    connect(ui->playUp,&QPushButton::clicked,this,&QQMusic::onplayUpClicked);
    //点击下一曲按钮的槽函数
    connect(ui->playDown,&QPushButton::clicked,this,&QQMusic::onplayDownClicked);
    //点击切换播放模式按钮的槽函数
    connect(ui->playMode,&QPushButton::clicked,this,&QQMusic::onPlaybackModeClicked);
    //播放列表的模式发生改变时的信号和槽函数关联
    connect(playList,&QMediaPlaylist::playbackModeChanged,this,&QQMusic::onPlaybackModeChanged);

    //likepage localpage recentpage三个页面中的播放所有按钮点击之后发射信号与槽函数的关联
    connect(ui->likePage,&CommonPage::playAll,this,&QQMusic::onPlayAll);
    connect(ui->localPage,&CommonPage::playAll,this,&QQMusic::onPlayAll);
    connect(ui->recentPage,&CommonPage::playAll,this,&QQMusic::onPlayAll);

    //处理likepage localpage recentpage三个页面中ListWidget中的Item被双击后立即播放双击的音乐槽函数的关联
    connect(ui->likePage,&CommonPage::playMusicByIndex,this,&QQMusic::playMusicByIndex);
    connect(ui->localPage,&CommonPage::playMusicByIndex,this,&QQMusic::playMusicByIndex);
    connect(ui->recentPage,&CommonPage::playMusicByIndex,this,&QQMusic::playMusicByIndex);

    //点击歌词按钮信号和槽函数关联
    connect(ui->lrcWord,&QPushButton::clicked,this,&QQMusic::onLrcWordClicked);

    //处理静音按钮发出的信号和槽函数关联
    connect(volumeTool,&VolumeTool::setMusicMuted,this,&QQMusic::setPlayerMuted);
    //处理调整音量大小信号和槽函数关联
    connect(volumeTool,&VolumeTool::setMusicVolume,this,&QQMusic::setPlayerVolume);

    //MusicSlider::setMusicSliderPosition
    //当进度条进度改变时，当前播放的音乐进度也改变的信号和槽函数的关联
    connect(ui->processBar,&MusicSlider::setMusicSliderPosition,this,&QQMusic::onMusicSliderChanged);

}
//管理图片的推荐文本和图片 RecBoxItem元素
QJsonArray QQMusic::randomPiction()
{
    //加载推荐文本和推荐图片
    //将图片随机化,随机推荐图片
    QVector<QString> vecImageName;
    vecImageName<<"001.png"<<"003.png"<<"004.png"<<"005.png"<<"006.png"<<"007.png"<<"008.png"<<"009.png"<<"010.png"<<"011.png"
                <<"012.png"<<"013.png"<<"014.png"<<"015.png"<<"016.png"<<"017.png"<<"018.png"<<"019.png"<<"020.png"<<"021.png"
                <<"022.png"<<"023.png"<<"024.png"<<"025.png"<<"026.png"<<"027.png"<<"028.png"<<"029.png"<<"030.png"<<"031.png"
                <<"032.png"<<"033.png"<<"034.png"<<"035.png"<<"036.png"<<"037.png"<<"038.png"<<"039.png"<<"040.png";
    //将vector中保存的资源名称随机化
    std::random_shuffle(vecImageName.begin(),vecImageName.end());
    //使用JSON方式将path和text信息进行保存
    //创建JSON数组
    QJsonArray objArray;
    //遍历vector，将JSON对象放到JSON数组中
    for(int i=0;i<vecImageName.size();i++)
    {
        //创建JSON对象
        QJsonObject obj;
        //添加信息
        obj.insert("path",":/images/rec/"+vecImageName[i]);
        QString strText=QString("推荐-%1").arg(i,3,10,QChar('0'));
        //                         占位符   具体数值  位数  进制  前面不够用什么字符补
        obj.insert("text",strText);
        //将JSON对象放到JSON数组中去
        objArray.append(obj);
    }
    return objArray;
}
//更新BtForm按钮上的动画
void QQMusic::updateBtformAnimal()
{
    //获取currentPage在stackedWidget中的索引
    int index=ui->stackedWidget->indexOf(currentPage);
    if(index==-1)
    {
        qDebug()<<"该页面不存在";
        return;
    }
    //获取QQMusic界面上所有的BtForm
    QList<BtForm*> btForms=this->findChildren<BtForm*>();
    //遍历这些BtForm按钮对象，寻找与此currentPage匹配的下标一致的BtForm对象
    for(BtForm* btForm:btForms)
    {
        //进行判断
        if(btForm->getpageId()==index)
        {
            //将currentPage对应的BtForm找到了
            //显示动画
            btForm->showAnimal(true);
        }
        else
        {
            //没找到currentPage对应的BtForm
            //将其他的BtForm上面的动画效果关闭
            btForm->showAnimal(false);
        }
    }
}
//让程序退出
void QQMusic::onQQMusicQuit()
{
    //将MusicList歌曲列表中的Music歌曲信息写入数据库
    musicList.writeToDB();
    //断开与SQLite的数据库连接
    sqlite.close();
    //关闭窗口
    close();
}

/* 拖拽功能
 * 拖拽时需要鼠标左键按下和鼠标移动来完成
 * 原理：记录鼠标按下时相对于屏幕左上角的坐标位置和当前程序窗口左上角相对于屏幕左上角的相对位置
 * 用这两个位置做差值，得到的就是鼠标位置相对于程序窗口左上角的相对位置
 * 只要保证在鼠标移动的时候，这个相对位置不改变，就完成了拖拽
 * 在鼠标左键点击事件时获取相对位置，在鼠标移动的时候保证相对位置不变，移动程序窗口即可。
*/

//鼠标按下事件的事件处理函数
void QQMusic::mousePressEvent(QMouseEvent *event)
{
    //检测是不是鼠标左键点击事件
    if(event->button()==Qt::LeftButton)
    {
        //当鼠标按下，就可以进行拖拽
        isDrag=true;
        //event->globalPos()：鼠标相对于屏幕左上角的位置
        //geometry().topLeft()：程序窗口左上角相对于屏幕左上角的相对位置
        //鼠标相对于程序窗口左上角的相对位置
        dragPosition=event->globalPos()-geometry().topLeft();
        return;
    }
    //剩下的鼠标事件都交给父类widget去进行处理
    QWidget::mousePressEvent(event);
}
//鼠标移动事件的事件处理函数
void QQMusic::mouseMoveEvent(QMouseEvent *event)
{
    //检测是鼠标左键点击事件
    //鼠标点击+可以移动时，再进行移动
    if(event->buttons()==Qt::LeftButton && isDrag==true)
    {
        //更新窗口位置
        //鼠标相对于屏幕左上角相对位置-相对位置=程序窗口左上角相对于屏幕左上角的相对位置
        //就可以实现更新窗口位置操作
        move(event->globalPos()-dragPosition);
        return;
    }
    //剩下的鼠标移动事件就交给父类widget进行处理
    QWidget::mouseMoveEvent(event);
}

//点击关闭按钮的槽函数
void QQMusic::on_quit_clicked()
{
    //将窗口进行隐藏
    this->hide();
}
//响应BtForm按钮btClick点击信号的槽函数。参数：点击按钮的id值
void QQMusic::onBtFormClick(int pageId)
{
    //清除之前BtForm按钮的背景颜色
    //获取所有的BtForm按钮对象
    QList<BtForm*> btFormList=this->findChildren<BtForm*>();
    //这是一个模板函数，我要找子类中所有的BtForm对象指针，返回一个list
    //遍历这个list并清除按钮的背景颜色
    for(BtForm* btForm : btFormList)
    {
        //如果此按钮的id不是当前按钮的id，即此按钮不是当前点击的按钮时，进行清除此按钮的背景颜色
        if(btForm->getpageId()!=pageId)
        {
            //清除此按钮的背景颜色
            btForm->clearBackground();
        }
    }

    //通过点击的按钮的id去展示stackedWidget的索引为pageId的page页面
    ui->stackedWidget->setCurrentIndex(pageId);
    qDebug()<<"切换页面:"<<pageId;
    //鼠标点击落在了BtForm按钮上时，不能进行拖拽
    isDrag=false;
}

/* 点击音量按键之后，由于是一个弹出窗口，就默认弹出到了屏幕的左上角
 * 这里，需要将这个弹出的音量调节窗口移动到正确的位置上
 * 原理：将ui->volumeTool这个音量按钮的基于屏幕的坐标获取到，然后借助这个坐标和音量按钮的宽度和高度参数
 * 对这个音量调节窗口进行调整位置即可
 */
//点击音量按键的槽函数
void QQMusic::on_volume_clicked()
{
    //1、获取音量调节按钮基于屏幕的坐标
    QPoint point=ui->volume->mapToGlobal(QPoint(0,0));//这个按钮基于它本身坐标就是(0，0)
    //QPoint mapToGlobal(QPoint对象)：将QPoint对象转换为基于屏幕的坐标
    //2、计算音量调节窗口需要移动到的位置
    QPoint volumeLeftTop=point-QPoint(volumeTool->width()/2,volumeTool->height());
    //微调音量调节窗口到音量按钮附加
    volumeLeftTop.setX(volumeLeftTop.x()+15);
    volumeLeftTop.setY(volumeLeftTop.y()+20);
    //3、移动音量调节窗口
    volumeTool->move(volumeLeftTop);
    //4、设置音量调节窗口进行显示
    volumeTool->show();
}
//点击添加音乐按钮的槽函数
void QQMusic::on_addLocal_clicked()
{
    //创建一个打开文件的对话框
    QFileDialog fileDialog(this);
    //设置窗口的标题
    fileDialog.setWindowTitle("添加本地下载音乐");
    //获取当前的项目exe文件所处的目录
    QDir dir(QDir::currentPath());
    //根据此目录进行调整到正确的路径
    dir.cdUp();//返回上一级目录
    QString projectPath=dir.path();//获取路径信息
    projectPath+="/QQMusic/musics";//添加路径
    qDebug()<<projectPath;//打印测试

    //设置打开文件对话框默认打开进入的目录
    fileDialog.setDirectory(projectPath);
    //设置一次性可以选择/打开多个文件
    fileDialog.setFileMode(QFileDialog::ExistingFiles);

    //通过文件后缀来过滤所显示的文件
//    fileDialog.setNameFilter("代码文件(*.h *.cpp *.c *.hpp)");
//    fileDialog.setNameFilter("图片文件(*.png *.jpg *.bmp)");
    //但是文件后缀特别多，通过文件后缀来过滤文件的话，代码就会显得特别臃肿，可以通过文件的MIME类型来过滤

    //通过MIME类型来过滤所显示的文件
    QStringList mimeTypeFilters;
    mimeTypeFilters<<"application/octet-stream";//相当与All(*)通用的二进制文件
    //通过MIME类型来过滤所显示的文件
    fileDialog.setMimeTypeFilters(mimeTypeFilters);

    //获取用户从此打开文件的对话框中选择的文件的信息,通过exec设置模态对话框函数的返回值来进行获取
    if(fileDialog.exec()==QDialog::Accepted)
    {
        //获取选中的文件的文件信息
        QList<QUrl> fileUrls=fileDialog.selectedUrls();
        //这个返回值中就存储的是刚刚用户从打开文件对话框中选中的文件的url路径
        //需要将这些文件填充到本地下载所对应的page中去

        //将所有音乐添加到音乐列表中MusicList
        musicList.addMusicsByUrl(fileUrls);
        //MusicList中管理的是解析之后的Music对象
        //将CommonPage切换到本地下载的page页面
        ui->stackedWidget->setCurrentIndex(4);

        //将Music更新到此本地下载page页面的ListWidget控件中
        ui->localPage->reFresh(musicList);
        //将localPage中的歌曲添加到媒体播放列表中
        //将musicList中的Music添加到playList播放列表中
        ui->localPage->addMusicToPlaylist(musicList,playList);
    }
}
//点击词按钮后的槽函数
void QQMusic::onLrcWordClicked()
{
    //点击词按钮后，让默认隐藏的这个lrc歌词界面显示出来
    lrcPage->show();
    //启动向上滑动动画
    lrcPageAnimal->start();
}
//收藏按钮已点击-更新我喜欢、本地下载、最近播放三个page页面所管理的Music列表信息
void QQMusic::updateLikeMusicAndPage(bool isLike, const QString &musicId)
{
    //1、修改Music的我喜欢的状态
    //通过MusicId寻找Music的迭代器
    iterator it=musicList.findMusicByMusicId(musicId);
    if(it!=musicList.end())
    {
        //找到了，更新状态
        it->setIsLike(isLike);
    }
    //2、更新这三个page页面的歌曲列表，并将其进行显示
    ui->likePage->reFresh(musicList);
    ui->localPage->reFresh(musicList);
    ui->recentPage->reFresh(musicList);

}
//播放控制区的槽函数

//点击播放按钮的槽函数-歌曲在播放和暂停之间进行切换-播放和暂停
void QQMusic::onPlayMusic()
{
    if(QMediaPlayer::PlayingState==player->state())
    {
        //如果是播放中状态，点击此按钮之后就暂停
        player->pause();//暂停
        //设置图片
        //ui->play->setIcon(QIcon(":/images/play3.png"));
    }
    else if(QMediaPlayer::PausedState==player->state())
    {
        //如果是暂停状态，点击之后就继续播放
        player->play();//播放
        //设置图片
        //ui->play->setIcon(QIcon(":/images/play_on.png"));
    }
    else if(QMediaPlayer::StoppedState==player->state())
    {
        //刚开始默认为停止状态，点击之后就直接播放即可
        player->play();
        //设置图片
        //ui->play->setIcon(QIcon(":/images/play_on.png"));
    }
    else
    {
        //此处就发生错误了，输出错误原因即可
        qDebug()<<player->errorString();
    }

}
//当播放按钮状态改变时的槽函数
//QMediaPlayer中stateChanged信号对应的槽函数
//状态改变对应的图片切换交给槽函数
void QQMusic::onPlayerStateChanged()
{
    if(player->state()==QMediaPlayer::PlayingState)
    {
        //正在播放状态，状态切换就是暂停状态
        ui->play->setIcon(QIcon(":/images/play_on.png"));
    }
    else
    {
        //暂停状态，切换状态就是继续播放状态
        ui->play->setIcon(QIcon(":/images/play3.png"));
    }
}
//点击上一曲按钮的槽函数
void QQMusic::onplayUpClicked()
{
    //设置播放列表为上一曲
    playList->previous();
}
//点击下一曲按钮的槽函数
void QQMusic::onplayDownClicked()
{
    //设置播放列表为下一曲
    playList->next();
}
//播放模式设置[随机播放、循环列表播放、单曲循环播放]
void QQMusic::onPlaybackModeClicked()
{
    //完成根据当前的播放模式，切换到下一个播放模式中
    //1、根据当前播放模式，切换到下一个播放模式
    //2、设置ToolTip提示
    //列表循环-随机播放-单曲循环
    //当状态发生改变时，还需要修改按钮上的图标
    //playbackMode()获取当前播放列表的播放模式
    //QMediaPlaylist::Loop 列表循环
    //QMediaPlaylist::Random 随机播放
    //QMediaPlaylist::CurrentItemInLoop 单曲循环
    if(playList->playbackMode()==QMediaPlaylist::Loop)
    {
        //列表循环->随机播放
        playList->setPlaybackMode(QMediaPlaylist::Random);
        //设置鼠标悬停时的提示信息
        ui->playMode->setToolTip("随机播放");
    }
    else if(playList->playbackMode()==QMediaPlaylist::Random)
    {
        //随机播放->单曲循环
        playList->setPlaybackMode(QMediaPlaylist::CurrentItemInLoop);
        //设置鼠标悬停时的提示信息
        ui->playMode->setToolTip("单曲循环");
    }
    else if(playList->playbackMode()==QMediaPlaylist::CurrentItemInLoop)
    {
        //单曲循环->列表循环
        playList->setPlaybackMode(QMediaPlaylist::Loop);
        //设置鼠标悬停时的提示信息
        ui->playMode->setToolTip("列表循环");
    }
    else
    {
        //暂不支持
        qDebug()<<"暂不支持";
    }
}
//当播放模式切换时的槽函数[随机播放、循环列表播放、单曲循环播放]之间互相切换时
void QQMusic::onPlaybackModeChanged(QMediaPlaylist::PlaybackMode playbackMode)
{
    //playbackMode参数表示当前最新的模式
    //完成图标的切换
    if(playbackMode==QMediaPlaylist::Loop)
    {
        ui->playMode->setIcon(QIcon(":/images/list_play.png"));
    }
    else if(playbackMode==QMediaPlaylist::Random)
    {
        ui->playMode->setIcon(QIcon(":/images/shuffle_2.png"));
    }
    else if(playbackMode==QMediaPlaylist::CurrentItemInLoop)
    {
        ui->playMode->setIcon(QIcon(":/images/single_play.png"));
    }
    else
    {
        qDebug()<<"暂不支持该模式";
    }
}
//点击播放所有按钮发射信号对应的槽函数
void QQMusic::onPlayAll(PageType pageType)
{
    //播放page对应的commonpage界面中的所有歌曲，默认从第0首开始播放
    //通过pageType找到对应的CommonPage页面
    CommonPage *page=ui->localPage;
    switch(pageType)
    {
    case PageType::LIKE_PAGE:
    {
        page=ui->likePage;
        break;
    }
    case PageType::LOCAL_PAGE:
    {
        page=ui->localPage;
        break;
    }
    case PageType::HISTORY_PAGE:
    {
        page=ui->recentPage;
        break;
    }
    default:
    {
        qDebug()<<"暂不支持的页面";
    }
    }

    //此处，就获取到了时哪个page页面(page)的全部播放按钮被点击了
    //page中记录的就是要播放的页面
    //播放page页面的播放列表中的全部音乐
    playAllMusicOfCommonPage(page,0);
}
//播放page页面的播放列表中的音乐,从第index首开始播放
void QQMusic::playAllMusicOfCommonPage(CommonPage *page, int index)
{
    //记录当前所处的页面
    currentPage=page;
    //更新BtForm按钮上的动画
    updateBtformAnimal();
    //清空之前的播放列表中的歌曲
    playList->clear();
    //添加当前要播放的page页面中的所有歌曲
    page->addMusicToPlaylist(musicList,playList);
    //设置默认从第index首歌曲开始播放
    playList->setCurrentIndex(index);
    //开始播放
    player->play();
}
//双击page页面中的音乐项时，void playMusicByIndex(CommonPage*,int)信号的槽函数，播放指定page页地址所处下标的音乐
void QQMusic::playMusicByIndex(CommonPage *page, int index)
{
    //播放page页面的播放列表中的音乐,从第index首开始播放
    playAllMusicOfCommonPage(page,index);
}
//playlist中播放源发生改变时，index表示正在播放的媒体的索引
void QQMusic::onCurrentIndexChanged(int index)
{
    //记录当前正在播放的音乐在播放列表中的索引
    currentIndex=index;
    //由于CommonPage页面中的歌曲和正在播放的播放列表中的歌曲的先后次序是相同的
    //知道歌曲在playlist中的索引之后，直接到CommonPage中获取
    //注意：playlist中的歌曲就是根据CommonPage中的musicOfPage加载
    //通过index下标来获取此Music的UUid
    QString musicId=currentPage->getMusicIdByIndex(index);
    //本意是想要通过索引拿到歌曲，然后修改歌曲的isHistory属性即可
    //通过MusicId来获取Music迭代器对象
    iterator it=musicList.findMusicByMusicId(musicId);
    if(it!=musicList.end())
    {
        //找到了，修改History属性
        it->setIsHistory(true);
    }
    //将最近播放的page页面进行刷新
    ui->recentPage->reFresh(musicList);
}
//媒体静音设置的自定义信号的槽函数-volimeTool类中setMusicMuted信号对应的槽函数
void QQMusic::setPlayerMuted(bool isMuted)
{
    //根据isMuted属性来设置是否静音
    player->setMuted(isMuted);
}
//发送音量大小需要调整信号的槽函数-volumnTool类中setMusicVolumn信号对应的槽函数
void QQMusic::setPlayerVolume(int volume)
{
    //根据volume改变音量大小
    player->setVolume(volume);
}
//当媒体源播放内容发生改变时对应信号的槽函数
void QQMusic::onDurationChanged(qint64 duration)
{
    //记录当前歌曲的总时间
    totalTime=duration;
    //duration为歌曲的总时长，单位为毫秒
    //需要将这个整形的总时长转化为min:sec形式
    //min:duration/1000/60
    //sec:duration/1000%60
    //更新总时长
    ui->totalTime->setText(QString("%1:%2").arg(duration/1000/60,2,10,QChar('0'))
                                           .arg(duration/1000%60,2,10,QChar('0')));

}
//播放进度发生改变时信号对应的槽函数
void QQMusic::onPositionChanged(qint64 position)
{
    //更新当前播放时间
    ui->currentTime->setText(QString("%1:%2").arg(position/1000/60,2,10,QChar('0'))
                             .arg(position/1000%60,2,10,QChar('0')));
    //更新进度条的位置
    ui->processBar->setStep(position/(float)totalTime);

    //如果有歌曲在播放时，才显示歌词
    if(currentIndex>=0)
    {
        //在歌词界面同步显示歌词
        lrcPage->showLrcWordLine(position);
    }


}
//进度条位置发生改变时的自定义信号，改变当前播放的音乐的进度的槽函数-进度条改变需要播放时间跟着进行修改
//进度条进度-媒体播放进度-当前播放时长进度 三者之间联动更新
void QQMusic::onMusicSliderChanged(float ration)
{
    //根据进度条与总宽度的比例，更新当前播放时间
    //获取当前已经播放时长
    qint64 duration=totalTime*ration;
    //更新当前播放时长
    ui->currentTime->setText(QString("%1:%2").arg(duration/1000/60,2,10,QChar('0'))
                                             .arg(duration/1000%60,2,10,QChar('0')));
    //当前播放时长更新，当前媒体播放进度也需要更新
    player->setPosition(duration);
}
//当媒体源发生改变时的槽函数-用于进行歌曲图片、歌手、专辑信息在播放控制区的加载 available表示元数据是否有效
void QQMusic::onMetaDataAvailableChanged(bool available)
{
    (void)available;
    //歌曲名称、歌曲作者直接到Music对象中获取
    //此时，需要知道媒体源在播放列表中的索引
    //获取当前播放的歌曲的id信息
    QString musicId=currentPage->getMusicIdByIndex(currentIndex);
    //通过歌曲id获取歌曲对象
    iterator it=musicList.findMusicByMusicId(musicId);
    //创建存储歌曲名称和作者的对象
    QString musicName("未知名称");
    QString musicSinger("未知歌手");
    //检测是否获取到有效的音乐对象
    if(it!=musicList.end())
    {
        //获取到了有效的音乐对象，赋值
        musicName=it->getMusicName();
        musicSinger=it->getMusicSinger();
    }
    //设置歌曲名称和歌曲作者的文本信息
    ui->musicName->setText(musicName);
    ui->musicSinger->setText(musicSinger);

    //通过元数据来获取封面图
    //获取封面图对象
    QVariant coverimage=player->metaData("ThumbnailImage");
    //检验此封面图是否有效
    if(coverimage.isValid()==true)
    {
        //封面图有效，设置封面图
        //获取此封面图的图片
        QImage image=coverimage.value<QImage>();
        //设置此图片为歌曲图片
        ui->musicCover->setPixmap(QPixmap::fromImage(image));
        //设置音乐图片 全部播放按钮旁边的图片
        currentPage->setMusicImage(QPixmap::fromImage(image));
    }
    else
    {
        //封面图无效，设置一个默认图片
        qDebug()<<"歌曲没有封面图";
        //默认图片路径
        QString path=":/images/rec/001.png";
        //设置此默认图片为歌曲图片
        ui->musicCover->setPixmap(path);
        //设置音乐图片 全部播放按钮旁边的图片
        currentPage->setMusicImage(path);
    }
    //为此图片设置自适应大小
    ui->musicCover->setScaledContents(true);

    //解析歌曲的Lrc歌词
    //检测此Music对象是否有效
    if(it!=musicList.end())
    {
        //此Music对象有效
        //获取此Music对象的lrc歌词文件路径
        QString lrcPath=it->getLrcFilePath();
        //解析此lrc歌词文件中的信息
        lrcPage->parseLrcFile(lrcPath);

    }

}
//点击换肤按钮的槽函数
void QQMusic::on_skin_clicked()
{
    //给窗口更换背景颜色 更换背景图片
    QMessageBox::information(this,"温馨提示","换肤功能正在支持中...");
}
//点击最小化按钮的槽函数
void QQMusic::on_min_clicked()
{
    //让窗口最小化显示
    showMinimized();
}
//点击最大化按钮的槽函数
void QQMusic::on_max_clicked()
{
    //让窗口最大化显示
    showMaximized();
}
